#! python
# -*- coding: utf-8 -*-
__author__ = "caiwanpeng"

import logging

from django.conf import settings
from celery import Celery
from celery.task import Task
from celery._state import _task_stack

project_name = settings.PROJECT_NAME
local_cache = settings.TASK_REDIS
local_env = settings.ENV_MODE


def custom_task_call(self, *args, **kwargs):
    """
    @desc 改造task方法使其适配edelay方法
    :param self:
    :param args:
    :param kwargs:
    :return:
    """
    dele_key = '{}_edelay_task_key'.format(project_name)
    task_key = kwargs.pop(dele_key, None)
    if task_key:
        redis_client = local_cache.client.get_client(write=True)
        if redis_client.exists(task_key):
            redis_client.delete(task_key)
    _task_stack.push(self)
    self.push_request()
    name = self.name
    try:
        if self.__self__ is not None:
            return self.run(self.__self__, *args, **kwargs)
        return self.run(*args, **kwargs)
    except Exception as e:
        message = u'celery.task 任务 %s，异常:%s，参数:%s' % (name, e, (args, kwargs))
        logging.error(message, exc_info=True)
    finally:
        self.pop_request()
        _task_stack.pop()


def custom_delay(self, *args, **kwargs):
    # 本机调试，不再异步执行。直接执行异步函数
    if local_env == 'local':
        return custom_task_call(self, *args, **kwargs)
    else:
        return self.apply_async(args, kwargs)


Task.__call__ = custom_task_call
Task.delay = custom_delay


def edelay(self, *args, **kwargs):
    """
    自定义celery异步调用, 当传入task_key时,会判断根据该值拼接的key,是否在redis中存在,存在,则标明 有任务执行或者待执行,
    不再抛该异步任务,当不存在时,设置key值,并设置过期时间,调用异步任务
    @param self:
    @param args:
    @param kwargs:
    countdown:设置超时时间
    @return:
    """
    key = kwargs.pop('edelay_key', None)
    try:
        countdown = int(kwargs.pop('countdown', 60))
    except:
        countdown = 60
    if countdown < 1 or countdown > 36000:
        raise ValueError(u'countdown值范围为1-36000')
    redis_client = local_cache.client.get_client(write=True)
    if key:
        key = project_name + '_edelay_' + str(key)
        if redis_client.exists(key):
            # 存在緩存,则任务任务刚执行,或者待执行,不再抛任务
            return None
        redis_client.set(key, 1, countdown)
        dele_key = '{}_edelay_task_key'.format(project_name)
        kwargs[dele_key] = key
        return self.apply_async(args, kwargs, countdown=countdown)
    else:
        raise ValueError(u'edelay_key为必要参数')


setattr(Task, 'edelay', edelay)